<?php

class DateUtil {

    public static function isDateSQL($date_string) {
        $date_array = explode("-", $date_string);
        if (count($date_array) == 3) {
            return checkdate($date_array[1], $date_array[2], $date_array[0]);
        }
        return false;
    }

    public static function isTimeSql($time_string) {
        $time_array = explode(':', $time_string);
        if (count($time_array) >= 2 or count($time_array) <= 3) {
            return
                    // Hour validation
                    preg_match('/^[0-2]?[0-9]$/', $time_array[0]) and intval($time_array[0]) <= 24 and
                    // Minute validation
                    preg_match('/^[0-5]?[0-9]$/', $time_array[1]) and
                    // second validation
                    (!isset($time_array[2]) or preg_match('/^[0-5]?[0-9]$/', $time_array[2]) );
        }
        return false;
    }

    public static function convertDateToSQL($date_convert, $format = "dd/mm/yyyy") {
        $pos = strpos($date_convert, '/');
        if ($pos === false)
            return $date_convert;

        switch ($format) {
            case "dd/mm/yyyy":
                list($day, $month, $year) = explode("/", $date_convert);
                break;
            case "mm/dd/yyyy":
                list($month, $day, $year) = explode("/", $date_convert);
                break;
        }

        if (($year == "1970") && ($month == "01" || $month == "1") && ($day == "01" || $day == "1"))
            return "1970-01-01";
        if (checkdate(intval($month), intval($day), intval($year)))
            return date("Y-m-d", mktime(0, 0, 0, intval($month), intval($day), intval($year)));

        return $date_convert;
    }

    public static function convertDatetimeToSQL($datetime_convert, $format = "dd/mm/yyyy") {
        $date = DateUtil::convertDateToSQL(substr($datetime_convert, 0, 10), $format);
        return $date . substr($datetime_convert, 10);
    }

    public static function diffTime($time_from, $time_to, $format = 'dhms') {
        $tmp_1 = strtotime($time_from);
        $tmp_2 = strtotime($time_to);
        $distance = $tmp_2 - $tmp_1;

        switch ($format) {
            case 'd':
                $day = floor($distance / 86400);
                return "$day d";
                break;
            case 'h':
                $hour = floor($distance / 3600);
                return "$hour h";
                break;
            case 'm':
                $min = floor($distance / 60);
                return "$min m";
                break;
            case 's':
                return "$distance s";
                break;
            case 'array':
            case 'dhms':
            default:
                $day = floor($distance / 86400);
                $distance = $distance % 86400;
                $hour = floor($distance / 3600);
                $distance = $distance % 3600;
                $min = floor($distance / 60);
                $s = $distance % 60;

                if ($format == 'array') {
                    return array("d" => $day, "h" => $hour, "m" => $min, "s" => $s);
                } else {
                    return "$day d $hour h $min m $s s";
                }
        }
    }
  
    public static function addDay($date, $day, $format = "Y/m/d") {
        $time = strtotime($date);
        return date($format, mktime(0, 0, 0, date("m", $time), $day + date("d", $time), date("y", $time)));
    }
    
    public static function addHour($date, $hour, $format = "Y-m-d H:i:s") {
        $time = strtotime($date);
        return date($format, $time + $hour * 60 * 60);
    }

    public static function addMonth($date, $month, $format = "Y/m/d") {
        $time = strtotime($date);
        return date($format, mktime(0, 0, 0, $month + date("m", $time), date("d", $time), date("y", $time)));
    }

    /**
     * Get a string (or other) representation of the date
     *
     * Get a string (or other) representation of this date in the
     * format specified by the DATE_FORMAT_* constants.
     *
     * @access public
     * @param int $format format constant (DATE_FORMAT_*) of the output date
     * @return string the date in the requested format
     */
    public static function getDate($format = DATE_FORMAT_ISO) {
        switch ($format) {
            case DATE_FORMAT_ISO:
                return $this->format("%Y-%m-%d %T");
                break;
            case DATE_FORMAT_ISO_BASIC:
                $format = "%Y%m%dT%H%M%S";
                if ($this->tz->getID() == 'UTC') {
                    $format .= "Z";
                }
                return $this->format($format);
                break;
            case DATE_FORMAT_ISO_EXTENDED:
                $format = "%Y-%m-%dT%H:%M:%S";
                if ($this->tz->getID() == 'UTC') {
                    $format .= "Z";
                }
                return $this->format($format);
                break;
            case DATE_FORMAT_ISO_EXTENDED_MICROTIME:
                $format = "%Y-%m-%dT%H:%M:%s";
                if ($this->tz->getID() == 'UTC') {
                    $format .= "Z";
                }
                return $this->format($format);
                break;
            case DATE_FORMAT_TIMESTAMP:
                return $this->format("%Y%m%d%H%M%S");
                break;
            case DATE_FORMAT_UNIXTIME:
                return mktime($this->hour, $this->minute, $this->second, $this->month, $this->day, $this->year);
                break;
            default:
                return $this->format($format);
        }
    }

    public static function parseDate($date_str, $format) {
        // Transform the format string in a pregexp
        $preg_format = preg_replace(
                array(
            '/[\(\)\{\}\[\]\?\.\*\+\/\\\\]/', // special regexp characters
            '/d/', // day of month with leading 0
            '/j/', // day of month without leading 0
            '/[mh]/', // month with leading 0 and 12-hour format of an hour with leading zeros
            '/[ng]/', // month without leading 0 and 12-hour format of an hour without leading zeros
            '/Y/', // year on 4 digit
            '/y/', // year on 2 digit
            '/[is]/', // minute and second with leading 0
            '/G/', // 24-hour format of an hour without leading zeros
            '/H/', // 24-hour format of an hour with leading zeros
            '/a/', // Lowercase Ante meridiem and Post meridiem
            '/A/' // Uppercase Ante meridiem and Post meridiem
                ), array(
            '\\\\$0', // special regexp characters
            '([0-3]\d)', // day of month with leading 0
            '([1-3]?\d)', // day of month without leading 0
            '([0-1]\d)', // month with leading 0 and 12-hour format of an hour with leading zeros
            '(1?\d)', // month without leading 0 and 12-hour format of an hour without leading zeros
            '(\d{4,})', // year on 4 digit
            '(\d{2})', // year on 2 digit
            '([0-5]\d)', // minute and second with leading 0
            '([1-2]?\d)', // 24-hour format of an hour without leading zeros
            '([0-2]\d)', // 24-hour format of an hour with leading zeros
            '([ap]m)', // Lowercase Ante meridiem and Post meridiem
            '([AP]M)' // Uppercase Ante meridiem and Post meridiem
                ), $format);

        // We get the list of format modifier in a simple matches array
        $count = preg_match_all('/[djmhngYyisGHaA]/', $format, $modifiers);
        // If the format contains no modifiers, we return an empty array
        if ($count == 0) {
            return array();
        }

        $count = preg_match_all('/' . $preg_format . '/', $date_str, $matches);
        // If there's no match, we know the date is in an invalid format, we return FALSE
        if ($count == 0) {
            return FALSE;
        }

        // Match modifier with their values
        $format_arr = array();
        $index = 1;
        foreach ($modifiers[0] as $modifier) {
            if ($modifier == 'A') {
                $format_arr['a'] = strtolower($matches[$index][0]);
            } else {
                $format_arr[$modifier] = $matches[$index][0];
            }
            ++$index;
        }

        // Construct the date structure
        $date = array('year' => 1900, 'month' => 1, 'day' => 1, 'hour' => 0, 'minute' => 0, 'second' => 0);

        foreach ($format_arr as $mod => $val) {
            $val = intval($val);
            switch ($mod) {
                case 'y' :
                    $date['year'] = 1900 + $val;
                    if ($val < 70) {
                        $date['year'] += 100;
                    }
                    break;
                case 'Y' :
                    $date['year'] = $val;
                    break;
                case 'm' :
                case 'n' :
                    $date['month'] = $val;
                    break;
                case 'd' :
                case 'j' :
                    $date['day'] = $val;
                    break;
                case 'i' :
                    $date['minute'] = $val;
                    break;
                case 's' :
                    $date['second'] = $val;
                    break;
                case 'g' :
                case 'h' :
                    $hour = $val;
                    if ($hour >= 1 and $hour <= 12) {
                        $hour %= $hour;
                        if (isset($format_arr['a']) and $format_arr['a'] == 'pm') {
                            $hour += 12;
                        }
                        $date['hour'] = $hour;
                    } else {
                        return FALSE;
                    }
                    break;
                case 'G' :
                case 'H' :
                    $hour = $val;
                    if ($hour >= 0 and $hour <= 23) {
                        $date['hour'] = $hour;
                    } else {
                        return FALSE;
                    }
                    break;
                default :
                    break;
            }
        }

        // Now validate the structure, then return it if it's ok
        if (checkdate($date['month'], $date['day'], $date['year'])) {
            return $date;
        } else {
            return FALSE;
        }
    }

    public static function formatDate($date, $format) {
        // Construct the date structure
        $date_new = array('year' => 1900, 'month' => 1, 'day' => 1, 'hour' => 0, 'minute' => 0, 'second' => 0);
        $date = array_merge($date_new, $date);
        $date['d'] = str_pad(strval($date['day']), 2, '0', STR_PAD_LEFT);
        $date['m'] = str_pad(strval($date['month']), 2, '0', STR_PAD_LEFT);
        $date['Y'] = str_pad(strval($date['year']), 4, '0', STR_PAD_LEFT);
        if ($date['year'] >= 1970 and $date['year'] <= 1999) {
            $date['y'] = strval($date['year'] - 1900);
        } elseif ($date['year'] >= 2000 and $date['year'] <= 2069) {
            $date['y'] = str_pad(strval($date['year'] - 2000), 2, '0', STR_PAD_LEFT);
        } else {
            $date['y'] = '70';
        }
        $date['a'] = ($date['hour'] < 12 ? 'am' : 'pm' );
        $date['A'] = strtoupper($date['a']);
        if ($date['hour'] >= 12) {
            $date['g'] = $date['hour'] - 12;
        } else {
            $date['g'] = $date['hour'];
        }
        if ($date['g'] == 0) {
            $date['g'] = '12';
        }

        $date['h'] = str_pad($date['g'], 2, '0', STR_PAD_LEFT);
        $date['H'] = str_pad(strval($date['hour']), 2, '0', STR_PAD_LEFT);
        $date['i'] = str_pad(strval($date['minute']), 2, '0', STR_PAD_LEFT);
        $date['s'] = str_pad(strval($date['second']), 2, '0', STR_PAD_LEFT);

        return str_replace(array('d', 'j', 'm', 'n', 'Y', 'y', 'a', 'A', 'g', 'h', 'G', 'H', 'i', 's'), array($date['d'], $date['day'], $date['m'], $date['month'], $date['Y'],
                    $date['y'], $date['a'], $date['A'], $date['g'], $date['h'],
                    $date['hour'], $date['H'], $date['i'], $date['s']), $format);
    }

    public static function isBetween($date, $start_date, $end_date) {

        if (datediff("d", $start_date, $date) >= 0 && datediff("d", $date, $end_date) >= 0) {
            return true;
        } else {
            return false;
        }
    }

}